// The design of the event system is based on SDL (www.libsdl.org)

#ifndef __YAVRSOMEGA_H
#define __YAVRSOMEGA_H

#include <string>
#include <queue>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cerrno>
#include <cstring>
#include <cmath>

#include <stdint.h>

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>

#define MAXBUFSIZE 1024
#define dataPort "27001"
#define msgPort "27000"

//! List of yavrs event types
enum yavrsEventTypes { YAVRS_WIIMOTE_EVENT, YAVRS_MOCAP_EVENT, YAVRS_NUNCHUK_EVENT };

#define YAVRS_EVENTMASK(X)	(1<<(X))
typedef enum
{
	YAVRS_WIIEVENTMASK = YAVRS_EVENTMASK(YAVRS_WIIMOTE_EVENT),
	YAVRS_MOCAPEVENTMASK = YAVRS_EVENTMASK(YAVRS_MOCAP_EVENT)
} yavrsEventMask;


//! List of wiimote buttons. Used for checking wiimote events to see which button was pressed.
enum wiimoteButtons { WIIMOTE_A, WIIMOTE_B, WIIMOTE_PLUS, WIIMOTE_HOME, WIIMOTE_MINUS, WIIMOTE_ONE, WIIMOTE_TWO,  WIIMOTE_UP, WIIMOTE_DOWN, WIIMOTE_LEFT, WIIMOTE_RIGHT };

//! List of service types from omegalib
enum ServiceType { POINTER, MOCAP, KEYBOARD, CONTROLLER, UI, GENERIC };

//! List of controller types from omegalib
enum ControllerTypes { XBOX, PS3, WIIMOTE, WII_NUNCHUK, WII_MOTIONPLUS };

//! Stores information about events from wiimotes
typedef struct yavrsWiimoteEvent
{
	uint8_t battery; //!< Battery percentage from 0 to 100

	int16_t accelX; //!< X Acceleration
	int16_t accelY; //!< Y Acceleration
	int16_t accelZ; //!< Z Acceleration

	//uint8_t buttons; //!< Button states
	bool a, b, up, down, left, right, plus, minus;

	//float yaw;
	//float pitch;
	//float roll;
} yavrsWiimoteEvent;

typedef struct yavrsNunchukEvent
{
	int16_t analogX, analogY;
	int16_t accelX, accelY, accelZ;
	bool c, z;
} yavrsNunchukEvent;

//! Stores information about events from motion capture devices
typedef struct yavrsMocapEvent
{
	float x; //!< X position
	float y; //!< Y position
	float z; //!< Z position

	struct {
		float x, y, z, w;
	} q; //!< Quaternion for orientation

} yavrsMocapEvent;

typedef union yavrsUnion
{
	yavrsWiimoteEvent wiimote; //!< Wiimote event
	yavrsMocapEvent mocap; //!< Mocap event
	yavrsNunchukEvent nunchuk; //!< Wii nunchuk
} yavrsUnion;

//! Stores information about events from input devices
typedef struct yavrsEvent
{
	uint8_t type; //!< The yavrs event type
	uint16_t sourceID; //!< Event source ID
	yavrsUnion data;

} yavrsEvent;

//! Connects to an omegaLib oinputserver and grabs events, storing them in an internal event queue.
class yavrsEventListener
{
public:
	//! Connects to an oinputserver and grabs events.
	/*!
	 *  \param hostname The hostname or ip to connect to
	*/
	yavrsEventListener(std::string);


	//! Closes the socket associated with the EventListener
	~yavrsEventListener();

	//! This function checks for new packets, calls an internal parsing function and then adds the event to the event queue. It then grabs the next event from the event queue and writes it into the passed yavrsEvent
	/*!
	 *  \param *event The address of a yavrsEvent (&myYavrsEvent)
	 */
	bool getNextEvent(yavrsEvent *event);


private:
	int sockfd; /*!< The socket file descriptor */
	int numBytesRecvd; /*! Stores the number of bytes received from socket reads */
	std::queue<yavrsEvent> eventQueue; /*! The internal event queue */
	char buffer[MAXBUFSIZE]; /*! Buffer for socket reads  */
	struct sockaddr_storage their_addr; /*! sockaddr for socket reads */
	socklen_t addr_len; /*! blah */

	/*!
	 * Parse a string into an event
	 */
	yavrsEvent parseEvent();
};

#endif


